home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / input / input_programs.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  27KB  |  837 lines

  1. /*****************************************************************************
  2.  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2002 VideoLAN
  5.  * $Id: input_programs.c,v 1.103 2003/03/12 05:26:46 sam Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>
  28. #include <string.h>                                    /* memcpy(), memset() */
  29.  
  30. #include <vlc/vlc.h>
  31.  
  32. #include "stream_control.h"
  33. #include "input_ext-intf.h"
  34. #include "input_ext-dec.h"
  35. #include "input_ext-plugins.h"
  36.  
  37. /*
  38.  * NOTICE : all of these functions expect you to have taken the lock on
  39.  * p_input->stream.lock
  40.  */
  41.  
  42. /* Navigation callbacks */
  43. static int ProgramCallback( vlc_object_t *, char const *,
  44.                             vlc_value_t, vlc_value_t, void * );
  45. static int TitleCallback( vlc_object_t *, char const *,
  46.                           vlc_value_t, vlc_value_t, void * );
  47. static int ChapterCallback( vlc_object_t *, char const *,
  48.                             vlc_value_t, vlc_value_t, void * );
  49. static int NavigationCallback( vlc_object_t *, char const *,
  50.                                vlc_value_t, vlc_value_t, void * );
  51.  
  52. /*****************************************************************************
  53.  * input_InitStream: init the stream descriptor of the given input
  54.  *****************************************************************************/
  55. int input_InitStream( input_thread_t * p_input, size_t i_data_len )
  56. {
  57.  
  58.     p_input->stream.i_stream_id = 0;
  59.  
  60.     /* initialized to 0 since we don't give the signal to the interface
  61.      * before the end of input initialization */
  62.     p_input->stream.b_changed = 0;
  63.     p_input->stream.pp_es = NULL;
  64.     p_input->stream.pp_selected_es = NULL;
  65.     p_input->stream.p_removed_es = NULL;
  66.     p_input->stream.p_newly_selected_es = NULL;
  67.     p_input->stream.pp_programs = NULL;
  68.     p_input->stream.p_selected_program = NULL;
  69.     p_input->stream.p_new_program = NULL;
  70.  
  71.     if( i_data_len )
  72.     {
  73.         if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
  74.         {
  75.             msg_Err( p_input, "out of memory" );
  76.             return 1;
  77.         }
  78.         memset( p_input->stream.p_demux_data, 0, i_data_len );
  79.     }
  80.     else
  81.     {
  82.         p_input->stream.p_demux_data = NULL;
  83.     }
  84.  
  85.     /* Create a few object variables used for navigation in the interfaces */
  86.     var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  87.     var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  88.     var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  89.     var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
  90.     var_AddCallback( p_input, "program", ProgramCallback, NULL );
  91.     var_AddCallback( p_input, "title", TitleCallback, NULL );
  92.     var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
  93.  
  94.     return 0;
  95. }
  96.  
  97. /*****************************************************************************
  98.  * input_EndStream: free all stream descriptors
  99.  *****************************************************************************/
  100. void input_EndStream( input_thread_t * p_input )
  101. {
  102.     /* Free navigation variables */
  103.     var_Destroy( p_input, "program" );
  104.     var_Destroy( p_input, "title" );
  105.     var_Destroy( p_input, "chapter" );
  106.  
  107.     /* Free all programs and associated ES, and associated decoders. */
  108.     while( p_input->stream.i_pgrm_number )
  109.     {
  110.         input_DelProgram( p_input, p_input->stream.pp_programs[0] );
  111.     }
  112.  
  113.     /* Free standalone ES */
  114.     while( p_input->stream.i_es_number )
  115.     {
  116.         input_DelES( p_input, p_input->stream.pp_es[0] );
  117.     }
  118.  
  119.     /* Free all areas */
  120.     while( p_input->stream.i_area_nb )
  121.     {
  122.         input_DelArea( p_input, p_input->stream.pp_areas[0] );
  123.     }
  124.  
  125.     /* Free selected ES */
  126.     if( p_input->stream.pp_selected_es != NULL )
  127.     {
  128.         free( p_input->stream.pp_selected_es );
  129.     }
  130.  
  131.     if( p_input->stream.p_demux_data != NULL )
  132.     {
  133.         free( p_input->stream.p_demux_data );
  134.     }
  135. }
  136.  
  137. /*****************************************************************************
  138.  * input_FindProgram: returns a pointer to a program described by its ID
  139.  *****************************************************************************/
  140. pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
  141.                                        uint16_t i_pgrm_id )
  142. {
  143.     unsigned int i;
  144.  
  145.     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
  146.     {
  147.         if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
  148.         {
  149.             return p_input->stream.pp_programs[i];
  150.         }
  151.     }
  152.  
  153.     return NULL;
  154. }
  155.  
  156. /*****************************************************************************
  157.  * input_AddProgram: add and init a program descriptor
  158.  *****************************************************************************
  159.  * This program descriptor will be referenced in the given stream descriptor
  160.  *****************************************************************************/
  161. pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
  162.                                       u16 i_pgrm_id, size_t i_data_len )
  163. {
  164.     /* Where to add the pgrm */
  165.     pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
  166.     vlc_value_t val;
  167.  
  168.     if( p_pgrm == NULL )
  169.     {
  170.         msg_Err( p_input, "out of memory" );
  171.         return NULL;
  172.     }
  173.  
  174.     /* Init this entry */
  175.     p_pgrm->i_number = i_pgrm_id;
  176.     p_pgrm->b_is_ok = 0;
  177.     p_pgrm->i_version = 0;
  178.  
  179.     p_pgrm->i_es_number = 0;
  180.     p_pgrm->pp_es = NULL;
  181.  
  182.     input_ClockInit( p_pgrm );
  183.  
  184.     p_pgrm->i_synchro_state = SYNCHRO_START;
  185.  
  186.     if( i_data_len )
  187.     {
  188.         p_pgrm->p_demux_data = malloc( i_data_len );
  189.         if( p_pgrm->p_demux_data == NULL )
  190.         {
  191.             msg_Err( p_input, "out of memory" );
  192.             return NULL;
  193.         }
  194.         memset( p_pgrm->p_demux_data, 0, i_data_len );
  195.     }
  196.     else
  197.     {
  198.         p_pgrm->p_demux_data = NULL;
  199.     }
  200.  
  201.     /* Add an entry to the list of program associated with the stream */
  202.     INSERT_ELEM( p_input->stream.pp_programs,
  203.                  p_input->stream.i_pgrm_number,
  204.                  p_input->stream.i_pgrm_number,
  205.                  p_pgrm );
  206.  
  207.     val.i_int = i_pgrm_id;
  208.     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val );
  209.  
  210.     return p_pgrm;
  211. }
  212.  
  213. /*****************************************************************************
  214.  * input_DelProgram: destroy a program descriptor
  215.  *****************************************************************************
  216.  * All ES descriptions referenced in the descriptor will be deleted.
  217.  *****************************************************************************/
  218. void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
  219. {
  220.     unsigned int i_pgrm_index;
  221.     vlc_value_t val;
  222.  
  223.     /* Find the program in the programs table */
  224.     for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
  225.          i_pgrm_index++ )
  226.     {
  227.         if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
  228.             break;
  229.     }
  230.  
  231.     /* If the program wasn't found, do nothing */
  232.     if( i_pgrm_index == p_input->stream.i_pgrm_number )
  233.     {
  234.         msg_Err( p_input, "program does not belong to this input" );
  235.         return;
  236.     }
  237.  
  238.     val.i_int = i_pgrm_index;
  239.     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val );
  240.  
  241.     /* Free the structures that describe the es that belongs to that program */
  242.     while( p_pgrm->i_es_number )
  243.     {
  244.         input_DelES( p_input, p_pgrm->pp_es[0] );
  245.     }
  246.  
  247.     /* Free the demux data */
  248.     if( p_pgrm->p_demux_data != NULL )
  249.     {
  250.         free( p_pgrm->p_demux_data );
  251.     }
  252.  
  253.     /* Remove this program from the stream's list of programs */
  254.     REMOVE_ELEM( p_input->stream.pp_programs,
  255.                  p_input->stream.i_pgrm_number,
  256.                  i_pgrm_index );
  257.  
  258.     /* Free the description of this program */
  259.     free( p_pgrm );
  260. }
  261.  
  262. /*****************************************************************************
  263.  * input_AddArea: add and init an area descriptor
  264.  *****************************************************************************
  265.  * This area descriptor will be referenced in the given stream descriptor
  266.  *****************************************************************************/
  267. input_area_t * input_AddArea( input_thread_t * p_input,
  268.                               uint16_t i_area_id, uint16_t i_part_nb )
  269. {
  270.     /* Where to add the pgrm */
  271.     input_area_t * p_area = malloc( sizeof(input_area_t) );
  272.     vlc_value_t val;
  273.     int i;
  274.  
  275.     if( p_area == NULL )
  276.     {
  277.         msg_Err( p_input, "out of memory" );
  278.         return NULL;
  279.     }
  280.  
  281.     /* Init this entry */
  282.     p_area->i_id = i_area_id;
  283.     p_area->i_part_nb = i_part_nb;
  284.     p_area->i_part= 0;
  285.     p_area->i_start = 0;
  286.     p_area->i_size = 0;
  287.     p_area->i_tell = 0;
  288.     p_area->i_seek = NO_SEEK;
  289.  
  290.     /* Add an entry to the list of program associated with the stream */
  291.     INSERT_ELEM( p_input->stream.pp_areas,
  292.                  p_input->stream.i_area_nb,
  293.                  p_input->stream.i_area_nb,
  294.                  p_area );
  295.  
  296.     /* Don't add empty areas */
  297.     if( i_part_nb == 0 )
  298.         return NULL;
  299.  
  300.     /* Take care of the navigation variables */
  301.     val.i_int = i_area_id;
  302.     var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val );
  303.  
  304.     val.psz_string = malloc( sizeof("title ") + 5 );
  305.     if( val.psz_string )
  306.     {
  307.         vlc_value_t val2;
  308.  
  309.         sprintf( val.psz_string, "title %2i", i_area_id );
  310.     var_Destroy( p_input, val.psz_string );
  311.     var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
  312.             VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
  313.     var_AddCallback( p_input, val.psz_string, NavigationCallback,
  314.              (void *)(int)i_area_id );
  315.  
  316.     var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val );
  317.  
  318.     for( i = 1; i <= i_part_nb; i++ )
  319.     {
  320.         val2.i_int = i;
  321.         var_Change( p_input, val.psz_string, VLC_VAR_ADDCHOICE, &val2 );
  322.     }
  323.     }
  324.  
  325.     return p_area;
  326. }
  327.  
  328. /*****************************************************************************
  329.  * input_SetProgram: changes the current program
  330.  *****************************************************************************/
  331. int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
  332. {
  333.     unsigned int i_es_index;
  334.     int i_required_audio_es;
  335.     int i_required_spu_es;
  336.     int i_audio_es = 0;
  337.     int i_spu_es = 0;
  338.     vlc_value_t val;
  339.  
  340.     if ( p_input->stream.p_selected_program )
  341.     {
  342.         for ( i_es_index = 1 ; /* 0 should be the PMT */
  343.                 i_es_index < p_input->stream.p_selected_program->
  344.                 i_es_number ;
  345.                 i_es_index ++ )
  346.         {
  347. #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
  348.             if ( p_es->p_decoder_fifo ) /* if the ES was selected */
  349.             {
  350.                 input_UnselectES( p_input , p_es );
  351.             }
  352. #undef p_es
  353.         }
  354.     }
  355.     /* Get the number of the required audio stream */
  356.     if( config_GetInt( p_input, "audio" ) )
  357.     {
  358.         /* Default is the first one */
  359.         i_required_audio_es = config_GetInt( p_input, "audio-channel" );
  360.         if( i_required_audio_es < 0 )
  361.         {
  362.             i_required_audio_es = 1;
  363.         }
  364.     }
  365.     else
  366.     {
  367.         i_required_audio_es = 0;
  368.     }
  369.  
  370.     /* Same thing for subtitles */
  371.     if( config_GetInt( p_input, "video" ) )
  372.     {
  373.         /* for spu, default is none */
  374.         i_required_spu_es = config_GetInt( p_input, "spu-channel" );
  375.         if( i_required_spu_es < 0 )
  376.         {
  377.             i_required_spu_es = 0;
  378.         }
  379.     }
  380.     else
  381.     {
  382.         i_required_spu_es = 0;
  383.     }
  384.  
  385.     for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
  386.     {
  387.         switch( p_new_prg->pp_es[i_es_index]->i_cat )
  388.         {
  389.             case VIDEO_ES:
  390.                 msg_Dbg( p_input, "selecting ES %x",
  391.                          p_new_prg->pp_es[i_es_index]->i_id );
  392.                 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
  393.                 break;
  394.             case AUDIO_ES:
  395.                 i_audio_es += 1;
  396.                 if( i_audio_es <= i_required_audio_es )
  397.                 {
  398.                     msg_Dbg( p_input, "selecting ES %x",
  399.                              p_new_prg->pp_es[i_es_index]->i_id );
  400.                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
  401.                 }
  402.                 break;
  403.             /* Not sure this one is fully specification-compliant */
  404.             case SPU_ES :
  405.                 i_spu_es += 1;
  406.                 if( i_spu_es <= i_required_spu_es )
  407.                 {
  408.                     msg_Dbg( p_input, "selecting ES %x",
  409.                              p_new_prg->pp_es[i_es_index]->i_id );
  410.                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
  411.                 }
  412.             break;
  413.             default :
  414.                 msg_Dbg( p_input, "ES %x has unknown type",
  415.                          p_new_prg->pp_es[i_es_index]->i_id );
  416.                 break;
  417.         }
  418.  
  419.     }
  420.  
  421.  
  422.     p_input->stream.p_selected_program = p_new_prg;
  423.  
  424.     /* Update the navigation variables without triggering a callback */
  425.     val.i_int = p_new_prg->i_number;
  426.     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val );
  427.  
  428.     return( 0 );
  429. }
  430.  
  431. /*****************************************************************************
  432.  * input_DelArea: destroy a area descriptor
  433.  *****************************************************************************
  434.  * All ES descriptions referenced in the descriptor will be deleted.
  435.  *****************************************************************************/
  436. void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
  437. {
  438.     unsigned int i_area_index;
  439.     vlc_value_t val;
  440.  
  441.     /* Find the area in the areas table */
  442.     for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
  443.          i_area_index++ )
  444.     {
  445.         if( p_input->stream.pp_areas[i_area_index] == p_area )
  446.             break;
  447.     }
  448.  
  449.     /* If the area wasn't found, do nothing */
  450.     if( i_area_index == p_input->stream.i_area_nb )
  451.     {
  452.         msg_Err( p_input, "area does not belong to this input" );
  453.         return;
  454.     }
  455.  
  456.     /* Take care of the navigation variables */
  457.     val.psz_string = malloc( sizeof("title ") + 5 );
  458.     if( val.psz_string )
  459.     {
  460.         sprintf( val.psz_string, "title %i", p_area->i_id );
  461.     var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val );
  462.     var_Destroy( p_input, val.psz_string );
  463.     }
  464.  
  465.     /* Remove this area from the stream's list of areas */
  466.     REMOVE_ELEM( p_input->stream.pp_areas,
  467.                  p_input->stream.i_area_nb,
  468.                  i_area_index );
  469.  
  470.     /* Free the description of this area */
  471.     free( p_area );
  472. }
  473.  
  474.  
  475. /*****************************************************************************
  476.  * input_FindES: returns a pointer to an ES described by its ID
  477.  *****************************************************************************/
  478. es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
  479. {
  480.     unsigned int i;
  481.  
  482.     for( i = 0; i < p_input->stream.i_es_number; i++ )
  483.     {
  484.         if( p_input->stream.pp_es[i]->i_id == i_es_id )
  485.         {
  486.             return p_input->stream.pp_es[i];
  487.         }
  488.     }
  489.  
  490.     return NULL;
  491. }
  492.  
  493. /*****************************************************************************
  494.  * input_AddES:
  495.  *****************************************************************************
  496.  * Reserve a slot in the table of ES descriptors for the ES and add it to the
  497.  * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
  498.  * alone (PSI ?)
  499.  *****************************************************************************/
  500. es_descriptor_t * input_AddES( input_thread_t * p_input,
  501.                                pgrm_descriptor_t * p_pgrm, u16 i_es_id,
  502.                                size_t i_data_len )
  503. {
  504.     es_descriptor_t * p_es;
  505.  
  506.     p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
  507.     if( p_es == NULL )
  508.     {
  509.         msg_Err( p_input, "out of memory" );
  510.         return( NULL);
  511.     }
  512.  
  513.     INSERT_ELEM( p_input->stream.pp_es,
  514.                  p_input->stream.i_es_number,
  515.                  p_input->stream.i_es_number,
  516.                  p_es );
  517.  
  518.     /* Init its values */
  519.     p_es->i_id = i_es_id;
  520.     p_es->psz_desc[0] = '\0';
  521.     p_es->p_pes = NULL;
  522.     p_es->p_decoder_fifo = NULL;
  523.     p_es->i_cat = UNKNOWN_ES;
  524.     p_es->i_demux_fd = 0;
  525.     p_es->c_packets = 0;
  526.     p_es->c_invalid_packets = 0;
  527.  
  528.     if( i_data_len )
  529.     {
  530.         p_es->p_demux_data = malloc( i_data_len );
  531.         if( p_es->p_demux_data == NULL )
  532.         {
  533.             msg_Err( p_input, "out of memory" );
  534.             return( NULL );
  535.         }
  536.         memset( p_es->p_demux_data, 0, i_data_len );
  537.     }
  538.     else
  539.     {
  540.         p_es->p_demux_data = NULL;
  541.     }
  542.     p_es->p_waveformatex     = NULL;
  543.     p_es->p_bitmapinfoheader = NULL;
  544.  
  545.     /* Add this ES to the program definition if one is given */
  546.     if( p_pgrm )
  547.     {
  548.         INSERT_ELEM( p_pgrm->pp_es,
  549.                      p_pgrm->i_es_number,
  550.                      p_pgrm->i_es_number,
  551.                      p_es );
  552.         p_es->p_pgrm = p_pgrm;
  553.     }
  554.     else
  555.     {
  556.         p_es->p_pgrm = NULL;
  557.     }
  558.  
  559.     return p_es;
  560. }
  561.  
  562. /*****************************************************************************
  563.  * input_DelES:
  564.  *****************************************************************************/
  565. void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
  566. {
  567.     unsigned int            i_index, i_es_index;
  568.     pgrm_descriptor_t *     p_pgrm;
  569.  
  570.     /* Find the ES in the ES table */
  571.     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
  572.          i_es_index++ )
  573.     {
  574.         if( p_input->stream.pp_es[i_es_index] == p_es )
  575.             break;
  576.     }
  577.  
  578.     /* If the ES wasn't found, do nothing */
  579.     if( i_es_index == p_input->stream.i_es_number )
  580.     {
  581.         msg_Err( p_input, "ES does not belong to this input" );
  582.         return;
  583.     }
  584.  
  585.     p_pgrm = p_es->p_pgrm;
  586.  
  587.     /* Kill associated decoder, if any. */
  588.     if( p_es->p_decoder_fifo != NULL )
  589.     {
  590.         input_EndDecoder( p_input, p_es );
  591.     }
  592.  
  593.     /* Remove this ES from the description of the program if it is associated to
  594.      * one */
  595.     if( p_pgrm )
  596.     {
  597.         for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
  598.         {
  599.             if( p_pgrm->pp_es[i_index] == p_es )
  600.             {
  601.                 REMOVE_ELEM( p_pgrm->pp_es,
  602.                              p_pgrm->i_es_number,
  603.                              i_index );
  604.                 break;
  605.             }
  606.         }
  607.     }
  608.  
  609.     /* Free the demux data */
  610.     if( p_es->p_demux_data != NULL )
  611.     {
  612.         free( p_es->p_demux_data );
  613.     }
  614.     if( p_es->p_waveformatex )
  615.     {
  616.         free( p_es->p_waveformatex );
  617.     }
  618.     if( p_es->p_bitmapinfoheader )
  619.     {
  620.         free( p_es->p_bitmapinfoheader );
  621.     }
  622.  
  623.     /* Find the ES in the ES table */
  624.     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
  625.          i_es_index++ )
  626.     {
  627.         if( p_input->stream.pp_es[i_es_index] == p_es )
  628.             break;
  629.     }
  630.  
  631.     /* Remove this ES from the stream's list of ES */
  632.     REMOVE_ELEM( p_input->stream.pp_es,
  633.                  p_input->stream.i_es_number,
  634.                  i_es_index );
  635.  
  636.     /* Free the ES */
  637.     free( p_es );
  638. }
  639.  
  640. /*****************************************************************************
  641.  * input_SelectES: selects an ES and spawns the associated decoder
  642.  *****************************************************************************
  643.  * Remember we are still supposed to have stream_lock when entering this
  644.  * function ?
  645.  *****************************************************************************/
  646. int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
  647. {
  648.     if( p_es == NULL )
  649.     {
  650.         msg_Err( p_input, "nothing to do in input_SelectES" );
  651.         return -1;
  652.     }
  653.  
  654.     if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
  655.         && !config_GetInt( p_input, "video" ) )
  656.     {
  657.         msg_Dbg( p_input,
  658.                  "video is disabled, not selecting ES 0x%x", p_es->i_id );
  659.         return -1;
  660.     }
  661.  
  662.     if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
  663.     {
  664.         msg_Dbg( p_input,
  665.                  "audio is disabled, not selecting ES 0x%x", p_es->i_id );
  666.         return -1;
  667.     }
  668.  
  669.     msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
  670.  
  671.     if( p_es->p_decoder_fifo != NULL )
  672.     {
  673.         msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
  674.         return -1;
  675.     }
  676.  
  677.     /* Release the lock, not to block the input thread during
  678.      * the creation of the thread. */
  679.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  680.     p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
  681.     vlc_mutex_lock( &p_input->stream.stream_lock );
  682.  
  683.     if( p_es->p_decoder_fifo == NULL )
  684.     {
  685.         return -1;
  686.     }
  687.  
  688.     return 0;
  689. }
  690.  
  691. /*****************************************************************************
  692.  * input_UnselectES: removes an ES from the list of selected ES
  693.  *****************************************************************************/
  694. int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
  695. {
  696.  
  697.     unsigned int i_index = 0;
  698.  
  699.     if( p_es == NULL )
  700.     {
  701.         msg_Err( p_input, "nothing to do in input_UnselectES" );
  702.         return -1;
  703.     }
  704.  
  705.     msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
  706.  
  707.     if( p_es->p_decoder_fifo == NULL )
  708.     {
  709.         msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
  710.         return( -1 );
  711.     }
  712.  
  713.     input_EndDecoder( p_input, p_es );
  714.     p_es->p_pes = NULL;
  715.  
  716.     if( ( p_es->p_decoder_fifo == NULL ) &&
  717.         ( p_input->stream.i_selected_es_number > 0 ) )
  718.     {
  719.         while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
  720.                ( p_input->stream.pp_selected_es[i_index] != p_es ) )
  721.         {
  722.             i_index++;
  723.         }
  724.  
  725.         /* XXX: no need to memmove, we have unsorted data */
  726.         REMOVE_ELEM( p_input->stream.pp_selected_es,
  727.                      p_input->stream.i_selected_es_number,
  728.                      i_index );
  729.  
  730.         if( p_input->stream.i_selected_es_number == 0 )
  731.         {
  732.             msg_Dbg( p_input, "no more selected ES" );
  733.             return 1;
  734.         }
  735.     }
  736.  
  737.     return 0;
  738. }
  739.  
  740. /*****************************************************************************
  741.  * Navigation callback: a bunch of navigation variables are used as an
  742.  *  alternative to the navigation API.
  743.  *****************************************************************************/
  744. static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
  745.                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
  746. {
  747.     input_thread_t *p_input = (input_thread_t *)p_this;
  748.  
  749.     if( oldval.i_int == newval.i_int )
  750.        return VLC_SUCCESS;
  751.  
  752.     vlc_mutex_lock( &p_input->stream.stream_lock );
  753.     if( ( newval.i_int > 0 ) )
  754.     {
  755.         vlc_mutex_unlock( &p_input->stream.stream_lock );
  756.         input_ChangeProgram( p_input, (uint16_t)newval.i_int );
  757.         input_SetStatus( p_input, INPUT_STATUS_PLAY );
  758.         vlc_mutex_lock( &p_input->stream.stream_lock );
  759.     }
  760.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  761.  
  762.     return VLC_SUCCESS;
  763. }
  764.  
  765. static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
  766.                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
  767. {
  768.     input_thread_t *p_input = (input_thread_t *)p_this;
  769.     input_area_t *p_area;
  770.  
  771.     if( oldval.i_int == newval.i_int )
  772.        return VLC_SUCCESS;
  773.  
  774.     /* Sanity check should have already be done by var_Set(). */
  775.     vlc_mutex_lock( &p_input->stream.stream_lock );
  776.     p_area = p_input->stream.pp_areas[newval.i_int];
  777.     p_area->i_part = 1;
  778.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  779.     input_ChangeArea( p_input, p_area );
  780.     input_SetStatus( p_input, INPUT_STATUS_PLAY );
  781.  
  782.     return VLC_SUCCESS;
  783. }
  784.  
  785. static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
  786.                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
  787. {
  788.     input_thread_t *p_input = (input_thread_t *)p_this;
  789.     input_area_t *p_area;
  790.  
  791.     if( oldval.i_int == newval.i_int )
  792.        return VLC_SUCCESS;
  793.  
  794.     /* Sanity check will have already be done by var_Set(). */
  795.     vlc_mutex_lock( &p_input->stream.stream_lock );
  796.     p_area = p_input->stream.p_selected_area;
  797.     p_input->stream.p_selected_area->i_part = newval.i_int;
  798.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  799.  
  800.     input_ChangeArea( p_input, p_area );
  801.     input_SetStatus( p_input, INPUT_STATUS_PLAY );
  802.  
  803.     return VLC_SUCCESS;
  804. }
  805.  
  806. static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
  807.                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
  808. {
  809.     input_thread_t *p_input = (input_thread_t *)p_this;
  810.     uint16_t i_area_id = (int)p_data;
  811.  
  812.     vlc_mutex_lock( &p_input->stream.stream_lock );
  813.  
  814.     if( p_input->stream.p_selected_area->i_id == i_area_id &&
  815.         oldval.i_int == newval.i_int )
  816.     {
  817.         /* Nothing to do */
  818.         vlc_mutex_unlock( &p_input->stream.stream_lock );
  819.         return VLC_SUCCESS;
  820.     }
  821.  
  822.     if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
  823.         ( (uint16_t)newval.i_int <=
  824.           p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
  825.     {
  826.         input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
  827.         p_input->stream.p_selected_area->i_part = newval.i_int;
  828.         vlc_mutex_unlock( &p_input->stream.stream_lock );
  829.         input_ChangeArea( p_input, p_area );
  830.         input_SetStatus( p_input, INPUT_STATUS_PLAY );
  831.         vlc_mutex_lock( &p_input->stream.stream_lock );
  832.     }
  833.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  834.  
  835.     return VLC_SUCCESS;
  836. }
  837.